package com.tjs.lucky.application.process;

import com.tjs.lucky.application.process.req.DrawProcessReq;
import com.tjs.lucky.application.process.res.DrawProcessResult;
import com.tjs.lucky.application.process.res.RuleQuantificationCrowdResult;
import com.tjs.lucky.common.*;
import com.tjs.lucky.domain.activity.model.req.PartakeReq;
import com.tjs.lucky.domain.activity.model.res.PartakeResult;
import com.tjs.lucky.domain.activity.model.vo.ActivityVO;
import com.tjs.lucky.domain.activity.repository.IActivityRepository;
import com.tjs.lucky.domain.activity.service.partake.IActivityPartake;
import com.tjs.lucky.domain.rule.mdel.req.DecisionValueReq;
import com.tjs.lucky.domain.rule.mdel.res.EngineResult;
import com.tjs.lucky.domain.rule.service.engine.EngineFilter;
import com.tjs.lucky.domain.strategy.model.vo.DrawAwardVO;
import com.tjs.lucky.domain.strategy.model.vo.DrawReq;
import com.tjs.lucky.domain.strategy.model.vo.DrawResult;
import com.tjs.lucky.domain.strategy.repository.IStrategyRepository;
import com.tjs.lucky.domain.strategy.service.draw.IDrawExec;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Objects;

/**
 * @Author: 田佳澍
 * @Description:
 * @DateTime: 2023/5/26 16:25
 **/
@Service
@Slf4j
public class ActivityProcess {

    @Resource
    private IActivityPartake activityPartake;

    @Resource
    private IDrawExec drawExec;

    @Resource(name = "ruleEngineHandle")
    private EngineFilter engineFilter;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IActivityRepository activityRepository;

    @Resource
    private IStrategyRepository strategyRepository;

    /**
     * 检查活动库存 和 奖品总库存是否充足
     *
     * @param activityId
     * @return
     */
    public boolean checkStock(Long activityId) {
        String actKey = "activityTotalCount:" + activityId;
        String activityTotalCount = stringRedisTemplate.opsForValue().get(actKey);
        String awardKey = "awardTotalStockCount:" + activityId;
        String awardTotalStockCount = stringRedisTemplate.opsForValue().get(awardKey);
        if (activityTotalCount == null || awardTotalStockCount == null) {
            ActivityVO activityVO = activityRepository.queryActivityInfo(activityId);
            activityTotalCount = String.valueOf(activityVO.getStockCount() == null ? -1 : activityVO.getStockCount());
            stringRedisTemplate.opsForValue().setIfAbsent(actKey, activityTotalCount);

            Integer totalAwardStock = strategyRepository.queryTotalAwardStock(activityVO.getStrategyId());
            awardTotalStockCount = String.valueOf(totalAwardStock == null ? -1 : totalAwardStock);
            stringRedisTemplate.opsForValue().set(awardKey, awardTotalStockCount);
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            stringRedisTemplate.opsForHash().putIfAbsent("activeActivitys",String.valueOf(activityId),dateFormat.format(activityVO.getEndDateTime()));
        }
        return Integer.parseInt(awardTotalStockCount) == 0 || Integer.parseInt(activityTotalCount) == 0;
    }

    /**
     * 抽奖
     *
     * @param req
     * @return
     */
    public DrawProcessResult doDrawProcess(DrawProcessReq req) {
        try {
            /*
                查询未参与的历史记录
             */
            PartakeResult partakeResult = activityPartake.queryActivityRecord(new PartakeReq(req.getUId(), req.getActivityId()));
            if(Objects.isNull(partakeResult)){
                // 1. 规则引擎量化，是否符合参与规则
                if (req.getRuleId() != null) {
                    RuleQuantificationCrowdResult ruleQuantificationCrowdResult = this.doRuleQuantificationCrowd(new DecisionValueReq(req.getRuleId(), req.getUId(), req.getValMap()));
                    if (!ResponseCode.SUCCESS.getCode().equals(ruleQuantificationCrowdResult.getCode())) {
                        log.error("量化人群抽奖，失败(规则引擎执行异常) uId：{} treeId：{}", req.getUId(), req.getRuleId());
                        return new DrawProcessResult(ruleQuantificationCrowdResult.getCode(), ruleQuantificationCrowdResult.getInfo());
                    }
                }
                // 2. 参与活动
                partakeResult = activityPartake.doPartake(new PartakeReq(req.getUId(), req.getActivityId()));
                if (!ResponseCode.SUCCESS.getCode().equals(partakeResult.getCode())) {
                    return new DrawProcessResult(partakeResult.getCode(), partakeResult.getInfo());
                }
            }
            Long strategyId = partakeResult.getStrategyId();
            Long takeId = partakeResult.getTakeId();

            // 3. 执行抽奖
            DrawResult drawResult = drawExec.doDrawExec(new DrawReq(req.getUId(), strategyId, String.valueOf(takeId), req.getActivityId()));
            if (DrawState.FAIL.getCode().equals(drawResult.getDrawState())) {
                return new DrawProcessResult(ResponseCode.LOSING_DRAW.getCode(), ResponseCode.LOSING_DRAW.getInfo());
            }
            DrawAwardVO drawAwardVO = drawResult.getDrawAwardInfo();
            drawAwardVO.setActivityLeftPartCount(partakeResult.getActivityLeftPartCount());
            drawAwardVO.setStrategyId(strategyId);
            // 4. 返回结果
            return new DrawProcessResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), drawAwardVO);
        } catch (Exception e) {
            return new DrawProcessResult(ResponseCode.UN_ERROR.getCode(), "抽奖过程发生异常");
        }
    }

    /**
     * 量化决策
     *
     * @param req
     * @return
     */
    private RuleQuantificationCrowdResult doRuleQuantificationCrowd(DecisionValueReq req) {
        // 1. 量化决策
        EngineResult engineResult = engineFilter.process(req);

        if (!engineResult.isSuccess()) {
            return new RuleQuantificationCrowdResult(ResponseCode.RULE_ERR.getCode(), ResponseCode.RULE_ERR.getInfo());
        }

        // 2. 封装结果
        RuleQuantificationCrowdResult ruleQuantificationCrowdResult = new RuleQuantificationCrowdResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo());
        ruleQuantificationCrowdResult.setActivityId(Long.valueOf(engineResult.getNodeValue()));

        return ruleQuantificationCrowdResult;
    }

}
